/********************************************
 * MODUL
 * 
 * Name: PROXY_PROCESS
 * 
 * Zweck: Zur quasi-parallelen verarbeitung der einelnen Clients
 *        leitet die Anfragen der Clients an den Server und die
 *        Antworten der Server an die Clients weiter
 *        Nutzt das tcp_socket_helper modul zur socket kommunikation
 * 
 * Autor(en): Simon Hinderhofer, Robert Lehmann, Benjamin Reiner, TIT08
 * 
 ********************************************/

#include <stdio.h>
#include <signal.h>	/* für SIGINT */

#include "proxy_process.h"
#include "tcp_socket_helper.h"

#define TRUE    1
#define FALSE   0

int terminated_proxy = FALSE;

/********************************************
 * FUNKTION
 * 
 * Name: sig_handler_summary(int signo)
 * 
 * Zweck: Signalhandling, wird hier genutzt um dem Prozess mitzuteilen, dass das Programm terminiert wurde
 * 
 * Parameter:
 * 	int signo: INPUT, eine signal ID
 * 
 * Globale Variablen:
 * 	int terminated: legt fest, ob das Programm vom Nutzer terminiert wurde
 * 
 * Rückgabewert:
 * 	nicht vorhanden
 * 
 ********************************************/
static void sig_handler_proxy(int signo)
{
  if (signo == SIGUSR2) 
  {
    /*send_data_to_summary_process(int bytes_read, int bytes_written);*/
    terminated_proxy = TRUE;
    signal(SIGUSR2, SIG_DFL);
  } 
  else if (signo == SIGINT)
  {
    signal(SIGINT, SIG_DFL);
  } 
  else if (signo == SIGUSR1)
  {
    signal(SIGUSR1, SIG_DFL);
  } 
  else 
  {
    printf("\nreceived signal %d\n\n", signo);
  }

  return;
}


/********************************************
 * FUNKTION
 *
 * Name: send_data_to_summary_process(int bytes_read, int bytes_written)
 *
 * Zweck: wenn der client die verbindung beendet, schickt der proxy prozess seine gesammelten daten
 *        (eingehende und ausgehende bytes) an den summary prozess und beendet sich selbst
 * Parameter:
 *   int bytes_read: INPUT, Anzahl der insgesamt gelesenen bytes
 *   int bytes_written, INPUT, Anzahl der insgesamt geschriebenen bytes
 *
 * Globale Variablen:
 * 	keine
 *
 * Rückgabewert:
 * 	nicht vorhanden
 *
 ********************************************/
void send_data_to_summary_process(int bytes_read, int bytes_written)
{
  int summary_socket;
  char buffer[64];
  int length;
  
  /* Verbinde zu summary_process */
  summary_socket = client_create_tcp_ipc_socket("summaryipc");
  
  /* Erstelle den zu sendenden String */
  length = sprintf(buffer, "read:%dwrite:%d", bytes_read, bytes_written);
  
  /* Sende diesen an den summary_process */
  write_tcp_socket(summary_socket, buffer);
  
  /* Schließe den Socket */
  close_tcp_socket(summary_socket);
}

/********************************************
 * FUNKTION
 *
 * Name: send_data_to_summary_process(int bytes_read, int bytes_written)
 *
 * Zweck: Hauptfunktion des proxy prozesses, leitet die daten vom client an den server weiter und vice versa
 *        zudem werden hier die signal handler des proxy prozesses registriert und die anzahl der requests und responses gezählt
 *
 * Parameter:
 *   int client_socket: INPUT, socket, der die verbindung des clients zum programm symbolisiert
 *   char server_host[]: INPUT, adresse des servers, auf den die anfragen weitergeleitet werden sollen
 *   unsigned short server_port: INPUT, port des servers, auf den die anfragen weitergeleitet werden sollen
 *   FILE* file: INPUT, datei, in die die logs geschrieben werden sollen
 *   int timeout: INPUT, timeout, nach dem ein proxy prozess bei inaktiver verbindung beenden soll
 *
 * Globale Variablen:
 * 	int terminated_proxy: gibt an, ob der proxy prozess noch weiterlaufen soll
 *
 * Rückgabewert:
 * 	nicht vorhanden
 *
 ********************************************/
void do_transmit(int client_socket, char server_host[], unsigned short server_port, FILE* file, int timeout)
{
  int socket_to_server;			/* socket descriptor für die gewünschte verbindung zum server */
  int counter_client = 1;		/* zählt, wie oft der client gesendet hat */
  int counter_server = 1;		/* zählt, wie oft der server gesendet hat */
  int sum_bytes_read = 0;		/* speichert die summe der gelesenen bytes */
  int sum_bytes_written = 0;		/* speichert die summe der geschriebenen bytes */
  struct tcp_transmit_struct result;	/* speichert den Rückgabewert der transmit_tcp_socket */
  
  result.byte_count = 0;
  result.flag = 0;
  
  /* Signalhandler registrieren nach Beispiel aus Vorlesung */
  if (signal(SIGUSR2, sig_handler_proxy) == SIG_ERR) 
  {
    fprintf(stderr, "ERROR: cannot catch SIGUSR1\n");
  }
  if (signal(SIGINT, sig_handler_proxy) == SIG_ERR) 
  {
    fprintf(stderr, "ERROR: cannot catch SIGINT\n");
  }
  if (signal(SIGUSR1, sig_handler_proxy) == SIG_ERR) 
  {
    fprintf(stderr, "ERROR: cannot catch SIGUSR1\n");
  }

  /* Verbinde zu dem gewünschten server */
  socket_to_server = client_create_tcp_socket(server_host, server_port);
  
  while (terminated_proxy == FALSE)
  {
    /* Leite Daten vom Client an Server weiter */
    result = transmit_tcp_socket(client_socket, socket_to_server, file, timeout, counter_client, counter_server, server_host, server_port);
    
    if (result.flag == -1)
    {
      terminated_proxy = TRUE;
    }
    else if (result.flag == 1)
    {
      sum_bytes_written = sum_bytes_written + result.byte_count;
      counter_client = counter_client +1;
    }
    else if (result.flag == 2)
    {
      sum_bytes_read = sum_bytes_read + result.byte_count;
      counter_server = counter_server +1;
    }
  }
    
  /* Schließe den Socket */
  close_tcp_socket(socket_to_server);
  close_tcp_socket(client_socket);
  
  /* sende die gespeicherten Daten per IPC an den summary_process */
  send_data_to_summary_process(sum_bytes_read, sum_bytes_written);
}
